/**********************************************************************************************
   plant_mood
   植物心情
   1.通过土壤湿度传感器（A0）获取土壤中的湿度（soilHumidity）。
   2.根据用户设定的该植物的适宜土壤湿度，通过数学模式计算得到植物心情。
   3.植物心情（0-5）的值对应了animation.h中的6个表情。
   4.当植物心情很差时，蜂鸣器（D5）发出声音，呼叫用户及时处理。
    Design By Peter
 *********************************************************************************************/
#include <TimerOne.h>
#include "animation.h"
//Pin connected to DS of 74HC595
int SER = 9;
//Pin connected to ST_CP of 74HC595
int RCK  = 10;
//Pin connected to SH_CP of 74HC595
int SRCK  = 11;
// A number indicating when to advance to the next frame
unsigned long nextImage = 0;
// A counter to know what frame we're showing
int animationIndex = 0;
// 8x8 led矩阵
byte brightnesses[64];
// 记录led矩阵帧数
int M[8];

//用户设定的植物适宜湿度
float setValue = 0;

//测得土壤湿度
float soilHumidity = 0;
void setup() {
  //set pins to output so you can control the shift register
  pinMode(RCK, OUTPUT);
  pinMode(SRCK, OUTPUT);
  pinMode(SER, OUTPUT);
  Serial.begin(9600);
}
void loop() {
  //读取土壤湿度
  soilHumidity = analogRead(A0) + 1;
  
  //用户设定的植物适宜湿度
  setValue = analogRead(A1) + 1;
 
  //串口输出测到湿度 
  Serial.println(String("soilHumidity:") + soilHumidity);
  //串口输出设定的适宜湿度
  Serial.println(String("setValue:") + setValue);
  
  //当测到的湿度大于设定的湿度
  if (setValue < soilHumidity)
  {
    //计算应该显示的图案序号
    animationIndex =  (5210 - 5 * soilHumidity) / (1025 - setValue);
  }
  else//测到的湿度小于设定的湿度
  { //计算应该显示的图案序号
    animationIndex = int((5 * soilHumidity) / setValue);
  }
 //如果测到的图案序号为，即处于极度不高兴状态,蜂鸣器报警
  if (animationIndex == 0)
  { 
    Serial.println(String("danger!"));
    tone(5, 532);
    delay(1000);
    noTone(5);
    delay(1000);
  }
  nextImage = animationDelays[animationIndex];
  Serial.println(animationIndex);
  //加载图片(converted)
  for (int i = 0; i < 64; i++) {
    brightnesses[i] = (animation[animationIndex][i / 4] >> (i % 4 * 2)) & B00000001;
    M[i / 8] |= (brightnesses[i] << (i % 8)) ;
  }
  //更新图片
  screenUpdate(nextImage);
  // animationIndex ++;
  //clear M[]
  for (int i = 0; i < (8); ++i) {
    M[i] = 0;
  }
}

void screenUpdate(unsigned long frametime)
{ // function to display image
  unsigned long startime = millis();
  while (millis() - startime < frametime)
  {
    byte row = B10000000; // row 1
    for (byte k = 0; k < 8; k++)
    {
      digitalWrite(RCK, LOW); // open latch ready to receive data
      shiftOut(~row); // row binary number
      shiftOut(M[k]); // LED array (inverted)
      // Close the latch, sending the data in the registers out to the matrix
      digitalWrite(RCK, HIGH);
      row = row >> 1; // bitshift right
    }
  }
}

//shift function
void shiftOut(byte myDataOut) {
  //internal function setup
  boolean pinState;

  //clear shift register read for sending data
  digitalWrite(RCK, LOW);
  // for each bit in dataOut send out a bit
  for (int i = 0; i <= 7; i++)  {
    //set clockPin to LOW prior to sending bit
    digitalWrite(SRCK, LOW);
    /*if the value of DataOut and (logical AND) a bitmask
      are true, set pinState to 1 (HIGH)*/
    if ( myDataOut & (1 << i) ) {
      pinState = HIGH;
    }
    else {
      pinState = LOW;
    }
    //Sets the pin to HIGH or LOW depending on pinState
    digitalWrite(SER, pinState);
    //send bit out on rising edge of clock
    digitalWrite(SRCK, HIGH);
    digitalWrite(SER, LOW);
  }
  //stop shifting
  digitalWrite(SRCK, LOW);
}
